using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using OracleInternal.Common;

namespace OracleInternal.Network
{
	internal class WebSocketStream : Stream
	{
		internal enum WebSocketRoles
		{
			WebSocketClient,
			WebSocketServer
		}

		internal enum WebSocketState
		{
			Open,
			Connecting,
			Connected,
			Closing,
			Closed,
			Error
		}

		private class WebSocketDataFrame
		{
			internal enum WebSocketDataFrameOpcode
			{
				CONTINUATION_FRAME = 0,
				TEXT_FRAME = 1,
				BINARY_FRAME = 2,
				CONNECTION_CLOSE = 8,
				PING = 9,
				PONG = 10
			}

			internal enum WebSocketDataFrameStatus : ushort
			{
				NORMAL_CLOSURE = 1000,
				GOING_AWAY,
				PROTOCOL_ERROR,
				UNACCEPTABLE_DATA
			}

			private const byte FIN = 128;

			private const byte RSV = 112;

			private byte OPCODE_MASK = 15;

			private byte PAYLOAD_MASK = 128;

			private byte PAYLOAD16 = 126;

			private byte PAYLOAD64 = 127;

			private const int WEBSOCKET_FIN_OPCODE_OFFSET = 0;

			private const int WEBSOCKET_FIN_OPCODE_LENGTH = 1;

			private const int WEBSOCKET_MASK_LENGTH7_OFFSET = 1;

			private const int WEBSOCKET_MASK_LENGTH7_LENGTH = 1;

			private const int WEBSOCKET_PAYLOAD16_OFFSET = 2;

			private const int WEBSOCKET_PAYLOAD16_LENGTH = 2;

			private const int WEBSOCKET_PAYLOAD64_OFFSET = 2;

			private const int WEBSOCKET_PAYLOAD64_LENGTH = 8;

			private const int WEBSOCKET_MASKKEY_LENGTH = 4;

			private const int WEBSOCKET_DATAFRAME_MIN_SIZE = 2;

			private const int WEBSOCKET_CONTROL_FRAME_DATA_LENGTH = 125;

			private const int WEBSOCKET_DATAFRAME_MAX_SIZE = 131;

			private byte[] m_dataframe;

			private int m_dataframe_length;

			private int m_dataframe_size;

			private int m_overflow_offset;

			private int m_overflow_length;

			private ulong m_payload_length;

			private bool m_Payload_Masked;

			private uint m_Payload_MaskKey;

			private WebSocketDataFrameOpcode m_Opcode;

			private byte[] m_control_data = new byte[125];

			private int m_control_data_length;

			internal byte[] FrameBuffer => m_dataframe;

			internal byte[] ControlData => m_control_data;

			internal int ControlDataLength
			{
				get
				{
					return m_control_data_length;
				}
				set
				{
					m_control_data_length = value;
				}
			}

			internal WebSocketDataFrameOpcode OpCode => m_Opcode;

			internal int FrameSize => m_dataframe_size;

			internal int Size => m_dataframe.Length;

			internal int Length
			{
				get
				{
					return m_dataframe_length;
				}
				set
				{
					m_dataframe_length = value;
				}
			}

			internal int Overflow
			{
				get
				{
					return m_overflow_length;
				}
				set
				{
					m_overflow_length = value;
				}
			}

			internal ulong PayloadLength
			{
				get
				{
					return m_payload_length;
				}
				set
				{
					m_payload_length = value;
				}
			}

			internal WebSocketDataFrame()
			{
				m_dataframe = new byte[131];
			}

			internal WebSocketDataFrame(int Size)
			{
				m_dataframe = new byte[Math.Max(Size, 131)];
			}

			internal void Clear()
			{
				Array.Clear(m_dataframe, 0, m_dataframe.Length);
				m_dataframe_length = 0;
				m_dataframe_size = 0;
				m_overflow_length = 0;
				m_payload_length = 0uL;
				m_Payload_Masked = false;
				m_Payload_MaskKey = 0u;
				m_Opcode = WebSocketDataFrameOpcode.CONTINUATION_FRAME;
			}

			internal int ReadWebSocketHeader()
			{
				if (m_dataframe_size > 0)
				{
					return 0;
				}
				if (Length == 0)
				{
					return 2;
				}
				if (Length >= 2)
				{
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, "WS: Processing meta data");
					}
					m_dataframe_size = 2;
					byte b = (byte)(m_dataframe[1] & ~PAYLOAD_MASK);
					if (b == PAYLOAD16)
					{
						m_dataframe_size += 2;
					}
					else if (b == PAYLOAD64)
					{
						m_dataframe_size += 8;
					}
					m_Payload_Masked = false;
					if ((m_dataframe[1] & PAYLOAD_MASK) != 0)
					{
						m_dataframe_size += 4;
						m_Payload_Masked = true;
					}
					if (Length < m_dataframe_size)
					{
						int result = m_dataframe_size - Length;
						m_dataframe_size = 0;
						return result;
					}
					m_Opcode = (WebSocketDataFrameOpcode)(m_dataframe[0] & OPCODE_MASK);
					if (m_Payload_Masked)
					{
						m_Payload_MaskKey = (uint)BitConverter.ToInt32(m_dataframe, m_dataframe_size - 4);
					}
					if (b == PAYLOAD16)
					{
						byte[] array = new byte[2];
						Array.Copy(m_dataframe, 2, array, 0, 2);
						if (BitConverter.IsLittleEndian)
						{
							Array.Reverse(array);
						}
						m_payload_length = (ulong)BitConverter.ToInt16(array, 0);
					}
					else if (b == PAYLOAD64)
					{
						byte[] array2 = new byte[8];
						Array.Copy(m_dataframe, 2, array2, 0, 8);
						if (BitConverter.IsLittleEndian)
						{
							Array.Reverse(array2);
						}
						m_payload_length = (ulong)BitConverter.ToInt64(array2, 0);
					}
					else
					{
						m_payload_length = b;
					}
					m_overflow_length = Length - m_dataframe_size;
					m_overflow_offset = m_dataframe_size;
					if (m_Opcode > WebSocketDataFrameOpcode.CONNECTION_CLOSE && m_payload_length != 0)
					{
						if ((ulong)m_overflow_length < m_payload_length)
						{
							m_dataframe_size = 0;
							return (int)((long)m_payload_length - (long)m_overflow_length);
						}
						m_control_data_length = GetOverflow(ControlData, 0, Overflow);
					}
					return 0;
				}
				return 2 - Length;
			}

			internal int GetOverflow(byte[] buffer, int offset, int count)
			{
				if (Overflow == 0)
				{
					return 0;
				}
				int num = Math.Min(Overflow, count);
				Array.Copy(FrameBuffer, m_overflow_offset, buffer, offset, num);
				Overflow -= num;
				m_overflow_offset += num;
				return num;
			}

			internal void CreateWebSocketFrame(bool FinalSegment, WebSocketDataFrameOpcode Opcode, bool MaskPayload, uint MaskKey, int PayloadSize)
			{
				if (Opcode >= WebSocketDataFrameOpcode.CONNECTION_CLOSE && PayloadSize > 125)
				{
					throw new ArgumentOutOfRangeException();
				}
				m_dataframe[0] = (byte)((FinalSegment ? 128u : 0u) | (byte)Opcode);
				m_dataframe[1] = (byte)(MaskPayload ? PAYLOAD_MASK : 0);
				if (PayloadSize < PAYLOAD16)
				{
					m_dataframe_length = 2;
					m_dataframe_size = 2;
					m_dataframe[1] |= (byte)PayloadSize;
				}
				else if (PayloadSize <= 65535)
				{
					m_dataframe_length = 4;
					m_dataframe_size = 2;
					m_dataframe[1] |= PAYLOAD16;
					byte[] bytes = BitConverter.GetBytes((ushort)PayloadSize);
					if (BitConverter.IsLittleEndian)
					{
						Array.Reverse(bytes);
					}
					Array.Copy(bytes, 0, m_dataframe, 2, 2);
					m_dataframe_size += 2;
				}
				else
				{
					m_dataframe_length = 10;
					m_dataframe_size = 10;
					m_dataframe[1] |= PAYLOAD64;
					byte[] bytes2 = BitConverter.GetBytes((ulong)PayloadSize);
					if (BitConverter.IsLittleEndian)
					{
						Array.Reverse(bytes2);
					}
					Array.Copy(bytes2, 0, m_dataframe, 2, 8);
					m_dataframe_size += 8;
				}
				m_payload_length = (ulong)PayloadSize;
				if (MaskPayload)
				{
					m_Payload_MaskKey = MaskKey;
					byte[] bytes3 = BitConverter.GetBytes(MaskKey);
					Array.Copy(bytes3, 0, m_dataframe, m_dataframe_size, bytes3.Length);
					m_dataframe_size += bytes3.Length;
				}
				else
				{
					m_Payload_MaskKey = 0u;
				}
				m_dataframe_length = m_dataframe_size;
			}
		}

		private const string CRLF = "\r\n";

		private const string HTTP_METHOD = "GET ";

		private const string HTTP_VERSION = "HTTP/1.1 ";

		private const string HOST_HEADER = "HOST: ";

		private const string ORACLE_WEBSOCKET_SERVER_HEADER = "Server: Oracle SQLNET Websocket Server";

		private const string UPGRADE_HEADER = "Upgrade: Websocket";

		private const string CONNECTION_HEADER = "Connection: Upgrade";

		private const string CONNECTION_CLOSE_HEADER = "Connection: Close";

		private const string AUTHORIZATION_HEADER = "Authorization: Basic ";

		private const string SWITCH_PROTOCOL_STATUS = "101 Switching Protocols";

		private const string BAD_REQUEST_STATUS = "400 Bad Request";

		private const string WEBSOCK_KEY_HEADER = "Sec-WebSocket-key: ";

		private const string WEBSOCK_ACCEPT_HEADER = "Sec-WebSocket-Accept: ";

		private const string WEBSOCK_PROTO_HEADER = "Sec-WebSocket-Protocol: ";

		private const string WEBSOCK_VER_HEADER = "Sec-WebSocket-Version: 13";

		private const string SERVER_HEADER = "SERVER: ";

		private const string DATE_HEADER = "DATE: ";

		private const string CONTENT_TYPE_HEADER = "Content-Type: text/html; charset=iso-8859-1";

		private const string WEBSOCK_SERVER_UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

		private const int SEC_WEBSOCKET_KEY_LENGTH = 16;

		private const int SEC_WEBSOCKET_KEY_HASH_LENGTH = 20;

		private const string HTTP_MESSAGE_HEADER_END = "\r\n\r\n";

		private const string HTTP_BAD_REQUEST_MESSAGE = "HTTP/1.1 400 Bad Request\r\nServer: Oracle SQLNET Websocket Server\r\nConnection: Close\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML>\r\n<head><title>400 Bad Request</title></head>\r\n<body><h1>Bad Request</h1><p>Could not understand client request.<br /></p></body>\r\n</html>\r\n";

		private const string HTTP_BAD_REQUEST_MESSAGE_END = "</html>\r\n";

		private const string DEFAUL_SUBPROTOCOL = "sqlnet.oracle.com";

		private const int WEBSOCKET_BUFFER_LENGTH = 512;

		private WebSocketRoles m_WebSocketRole;

		private ConnectionOption m_conOption;

		private Stream m_TcpStream;

		private WebSocketState m_WebSocketState;

		private byte[] m_Sec_WebSocket_Key = new byte[16];

		private string m_b64_Sec_WebSocket_Key;

		private string m_Sec_WebSock_Accept;

		private byte[] m_WebSocket_Buffer = new byte[512];

		private WebSocketDataFrame m_rcv_frame_buf;

		private WebSocketDataFrame m_snd_frame_buf;

		internal WebSocketRoles WebSocketRole => m_WebSocketRole;

		internal WebSocketState State => m_WebSocketState;

		public override long Position
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public override long Length
		{
			get
			{
				throw new NotImplementedException();
			}
		}

		public override bool CanRead => true;

		public override bool CanSeek => false;

		public override bool CanWrite => true;

		internal WebSocketStream(ConnectionOption conOption, Stream TcpStream)
		{
			m_conOption = conOption;
			m_TcpStream = TcpStream;
			m_rcv_frame_buf = new WebSocketDataFrame();
			m_rcv_frame_buf.Clear();
			m_snd_frame_buf = new WebSocketDataFrame();
			m_snd_frame_buf.Clear();
			m_WebSocketState = WebSocketState.Open;
		}

		internal void SetStream(Stream TcpStream)
		{
			m_TcpStream = TcpStream;
		}

		internal void Handshake(WebSocketRoles role)
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Handshake);
			}
			m_WebSocketRole = role;
			try
			{
				if (m_WebSocketRole == WebSocketRoles.WebSocketClient)
				{
					SendHandshakeRequest();
					m_WebSocketState = WebSocketState.Connecting;
					ParseHandshakeResponse();
				}
				else
				{
					ParseHandshakeRequest();
					m_WebSocketState = WebSocketState.Connecting;
					SendHandshakeResponse();
				}
			}
			catch (Exception inner)
			{
				throw new NetworkException(-6412, inner);
			}
			m_WebSocketState = WebSocketState.Connected;
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Handshake);
			}
		}

		public override void Close()
		{
			if (State == WebSocketState.Connected || State == WebSocketState.Error)
			{
				byte[] array = ((State != WebSocketState.Connected) ? BitConverter.GetBytes((ushort)1002) : BitConverter.GetBytes((ushort)1000));
				if (BitConverter.IsLittleEndian)
				{
					Array.Reverse(array);
				}
				try
				{
					SendControlFrame(WebSocketDataFrame.WebSocketDataFrameOpcode.CONNECTION_CLOSE, array, 0, array.Length);
				}
				catch (Exception)
				{
				}
				m_WebSocketState = WebSocketState.Closed;
			}
			else if (State == WebSocketState.Closing)
			{
				int count = Math.Min(m_rcv_frame_buf.ControlDataLength, 2);
				try
				{
					SendControlFrame(WebSocketDataFrame.WebSocketDataFrameOpcode.CONNECTION_CLOSE, m_rcv_frame_buf.ControlData, 0, count);
				}
				catch (Exception)
				{
				}
				m_WebSocketState = WebSocketState.Closed;
			}
			if (State == WebSocketState.Closed)
			{
				m_TcpStream = null;
				base.Close();
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			int num = 0;
			bool flag = true;
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read);
			}
			while (flag)
			{
				int count2;
				while ((count2 = m_rcv_frame_buf.ReadWebSocketHeader()) > 0)
				{
					try
					{
						num = m_TcpStream.Read(m_rcv_frame_buf.FrameBuffer, m_rcv_frame_buf.Length, count2);
					}
					catch (Exception ex)
					{
						if (ProviderConfig.m_bTraceLevelNetwork)
						{
							_trace("Attempted to read " + count2 + " bytes for frame header");
						}
						if (ProviderConfig.m_bTraceLevelNetwork)
						{
							_trace("Exception occured - " + ex.ToString());
						}
						throw ex;
					}
					if (num > 0)
					{
						m_rcv_frame_buf.Length += num;
						continue;
					}
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read);
					}
					return 0;
				}
				if (m_rcv_frame_buf.OpCode >= WebSocketDataFrame.WebSocketDataFrameOpcode.CONNECTION_CLOSE)
				{
					if (m_rcv_frame_buf.OpCode == WebSocketDataFrame.WebSocketDataFrameOpcode.CONNECTION_CLOSE)
					{
						m_WebSocketState = WebSocketState.Closing;
						Close();
						return 0;
					}
					if (m_rcv_frame_buf.OpCode == WebSocketDataFrame.WebSocketDataFrameOpcode.PING)
					{
						try
						{
							SendControlFrame(WebSocketDataFrame.WebSocketDataFrameOpcode.PONG, m_rcv_frame_buf.ControlData, 0, m_rcv_frame_buf.ControlDataLength);
						}
						catch (Exception)
						{
						}
						m_rcv_frame_buf.Clear();
						continue;
					}
					if (m_rcv_frame_buf.OpCode != WebSocketDataFrame.WebSocketDataFrameOpcode.PONG)
					{
						m_WebSocketState = WebSocketState.Error;
						Close();
						return 0;
					}
					m_rcv_frame_buf.Clear();
				}
				else
				{
					flag = false;
				}
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, "WS incoming Data Frame : frame length  = " + m_rcv_frame_buf.FrameSize + ", payload length = " + m_rcv_frame_buf.PayloadLength);
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, "WS incoming Data Frame meta data :");
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Receive, m_rcv_frame_buf.FrameBuffer, 0, m_rcv_frame_buf.FrameSize);
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, "WS buffer has overflow of " + m_rcv_frame_buf.Overflow + ", requested to read " + count + " bytes");
			}
			num = m_rcv_frame_buf.GetOverflow(buffer, offset, count);
			if (num > 0)
			{
				m_rcv_frame_buf.PayloadLength -= (ulong)num;
				if (m_rcv_frame_buf.PayloadLength == 0L)
				{
					m_rcv_frame_buf.Clear();
				}
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read);
				}
				return num;
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, "WS reads pay load from network");
			}
			int num2 = num;
			int num3 = count - num;
			int count3 = 0;
			while (num3 > 0 && m_rcv_frame_buf.PayloadLength != 0)
			{
				try
				{
					count3 = (((ulong)num3 > m_rcv_frame_buf.PayloadLength) ? ((int)m_rcv_frame_buf.PayloadLength) : num3);
					num = m_TcpStream.Read(buffer, offset + num2, count3);
				}
				catch (Exception ex3)
				{
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						_trace("Attempted to read " + count3 + " bytes of  pay load");
					}
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						_trace("Exception occured - " + ex3.ToString());
					}
					throw ex3;
				}
				if (num > 0)
				{
					num2 += num;
					num3 -= num;
					m_rcv_frame_buf.PayloadLength -= (ulong)num;
					continue;
				}
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read);
				}
				return 0;
			}
			if (m_rcv_frame_buf.PayloadLength == 0L)
			{
				m_rcv_frame_buf.Clear();
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read);
			}
			return num2;
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Write);
			}
			bool maskPayload = ((m_WebSocketRole == WebSocketRoles.WebSocketClient) ? true : false);
			m_snd_frame_buf.CreateWebSocketFrame(FinalSegment: true, WebSocketDataFrame.WebSocketDataFrameOpcode.BINARY_FRAME, maskPayload, 0u, count);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Write, "WS out-going Data Frame : frame size = " + m_snd_frame_buf.FrameSize + ", payload length = " + m_snd_frame_buf.PayloadLength);
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.BulkCopy, m_snd_frame_buf.FrameBuffer, 0, m_snd_frame_buf.FrameSize);
			}
			m_TcpStream.Write(m_snd_frame_buf.FrameBuffer, 0, m_snd_frame_buf.Length);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Write, "WS sends payload of " + count + " bytes");
			}
			m_TcpStream.Write(buffer, offset, count);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Write);
			}
		}

		public override void SetLength(long value)
		{
			throw new NotImplementedException();
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			throw new NotImplementedException();
		}

		public override void Flush()
		{
			m_TcpStream.Flush();
		}

		private void SendHandshakeRequest()
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.SendHandshakeRequest);
			}
			new Random().NextBytes(m_Sec_WebSocket_Key);
			m_b64_Sec_WebSocket_Key = Convert.ToBase64String(m_Sec_WebSocket_Key);
			string text = (string.IsNullOrEmpty(m_conOption.WEBSOCK_URI) ? m_conOption.SNOConfig.SQLNetURI : m_conOption.WEBSOCK_URI);
			if (text.IndexOf("/", 0) != 0)
			{
				text = "/" + text;
			}
			string text2 = "GET " + text + " HTTP/1.1 \r\nHOST: " + m_conOption.Host + "\r\nUpgrade: Websocket\r\nConnection: Upgrade\r\nSec-WebSocket-key: " + m_b64_Sec_WebSocket_Key + "\r\nSec-WebSocket-Protocol: sqlnet.oracle.com\r\nSec-WebSocket-Version: 13\r\n";
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.SendHandshakeRequest, "WS Handshake request :\n" + text2);
			}
			text2 += "\r\n";
			byte[] bytes = new ASCIIEncoding().GetBytes(text2);
			m_TcpStream.Write(bytes, 0, bytes.Length);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.SendHandshakeRequest);
			}
		}

		private void ParseHandshakeRequest()
		{
			List<string> hankshakeMessage = GetHankshakeMessage();
			if (hankshakeMessage == null)
			{
				throw new NetworkException(-6410);
			}
			string sQLNetURI = m_conOption.SNOConfig.SQLNetURI;
			string a = Regex.Replace(hankshakeMessage[0], "\\s+", " ");
			if (!string.Equals(a, "GET " + sQLNetURI + " HTTP/1.1 ", StringComparison.InvariantCultureIgnoreCase))
			{
				throw new NetworkException(-6410);
			}
			for (int i = 1; i < hankshakeMessage.Count; i++)
			{
				a = Regex.Replace(hankshakeMessage[i], "\\s+", " ");
				if (string.Equals(a, "Upgrade: Websocket", StringComparison.InvariantCultureIgnoreCase) || string.Equals(a, "Connection: Upgrade", StringComparison.InvariantCultureIgnoreCase) || string.Equals(a, "Sec-WebSocket-Protocol: sqlnet.oracle.com", StringComparison.InvariantCultureIgnoreCase) || string.Equals(a, "Sec-WebSocket-Version: 13", StringComparison.InvariantCultureIgnoreCase))
				{
					continue;
				}
				char separator = ' ';
				string[] array = a.Split(separator);
				if (string.Equals(array[0], "HOST: ", StringComparison.InvariantCultureIgnoreCase))
				{
					continue;
				}
				if (string.Equals(array[0], "Sec-WebSocket-key: ", StringComparison.InvariantCultureIgnoreCase))
				{
					m_b64_Sec_WebSocket_Key = array[1];
					continue;
				}
				if (array.Length > 2)
				{
					if (!string.Equals(array[0] + " " + array[1], "Authorization: Basic ", StringComparison.InvariantCultureIgnoreCase))
					{
						throw new NetworkException(-6410);
					}
					continue;
				}
				throw new NetworkException(-6410);
			}
		}

		private void SendHandshakeResponse()
		{
			string str = GenerateResponseKey(m_b64_Sec_WebSocket_Key);
			string s = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: Websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " + str + "\r\nSec-WebSocket-Protocol: sqlnet.oracle.com\r\nSec-WebSocket-Version: 13\r\n\r\n";
			byte[] bytes = new ASCIIEncoding().GetBytes(s);
			m_TcpStream.Write(bytes, 0, bytes.Length);
		}

		private void SendBadRequestResponse()
		{
			byte[] bytes = new ASCIIEncoding().GetBytes("HTTP/1.1 400 Bad Request\r\nServer: Oracle SQLNET Websocket Server\r\nConnection: Close\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML>\r\n<head><title>400 Bad Request</title></head>\r\n<body><h1>Bad Request</h1><p>Could not understand client request.<br /></p></body>\r\n</html>\r\n");
			m_TcpStream.Write(bytes, 0, bytes.Length);
		}

		private void ParseHandshakeResponse()
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.ParseHandshakeResponse);
			}
			List<string> hankshakeMessage = GetHankshakeMessage();
			if (hankshakeMessage == null)
			{
				throw new NetworkException(-6411);
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				string text = null;
				for (int i = 0; i < hankshakeMessage.Count; i++)
				{
					text = text + hankshakeMessage[i] + "\n";
				}
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, "WS Handshake response :\n" + text);
			}
			string a = Regex.Replace(hankshakeMessage[0], "\\s+", " ");
			if (!string.Equals(a, "HTTP/1.1 101 Switching Protocols", StringComparison.InvariantCultureIgnoreCase))
			{
				throw new NetworkException(-6411);
			}
			for (int j = 1; j < hankshakeMessage.Count; j++)
			{
				a = Regex.Replace(hankshakeMessage[j], "\\s+", " ");
				if ((a == "" && j == hankshakeMessage.Count - 1) || string.Equals(a, "Upgrade: Websocket", StringComparison.InvariantCultureIgnoreCase) || string.Equals(a, "Connection: Upgrade", StringComparison.InvariantCultureIgnoreCase) || string.Equals(a, "Sec-WebSocket-Protocol: sqlnet.oracle.com", StringComparison.InvariantCultureIgnoreCase) || string.Equals(a, "Sec-WebSocket-Version: 13", StringComparison.InvariantCultureIgnoreCase))
				{
					continue;
				}
				char separator = ' ';
				string[] array = a.Split(separator);
				if (string.Equals(array[0], "Sec-WebSocket-Accept: ".Trim(), StringComparison.InvariantCultureIgnoreCase))
				{
					string text2 = array[1].Trim();
					if (text2.Length <= 0)
					{
						continue;
					}
					string b = GenerateResponseKey(m_b64_Sec_WebSocket_Key);
					if (!string.Equals(text2, b, StringComparison.Ordinal))
					{
						if (ProviderConfig.m_bTraceLevelNetwork)
						{
							OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, text2 + "is an invalid response key.\n");
						}
						throw new NetworkException(-6411);
					}
				}
				else if (!string.Equals(array[0], "SERVER: ".Trim(), StringComparison.InvariantCultureIgnoreCase) && !string.Equals(array[0], "DATE: ".Trim(), StringComparison.InvariantCultureIgnoreCase))
				{
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, array[0].ToString() + "header is invalid.\n");
					}
					throw new NetworkException(-6411);
				}
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.ParseHandshakeResponse);
			}
		}

		private List<string> GetHankshakeMessage()
		{
			bool flag = false;
			string text = null;
			ASCIIEncoding aSCIIEncoding = new ASCIIEncoding();
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.GetHankshakeMessage);
			}
			do
			{
				int num = m_TcpStream.Read(m_WebSocket_Buffer, 0, m_WebSocket_Buffer.Length);
				if (num > 0)
				{
					text += aSCIIEncoding.GetString(m_WebSocket_Buffer, 0, num);
					if (text.Length > "\r\n\r\n".Length)
					{
						if (text.Substring(text.Length - "\r\n\r\n".Length).Equals("\r\n\r\n", StringComparison.InvariantCultureIgnoreCase))
						{
							flag = true;
						}
						else if (text.Substring(text.Length - "</html>\r\n".Length).Equals("</html>\r\n", StringComparison.InvariantCultureIgnoreCase))
						{
							flag = true;
						}
					}
					continue;
				}
				throw new NetworkException(-6412);
			}
			while (!flag);
			List<string> list = new List<string>();
			int num2 = 0;
			while (num2 < text.Length)
			{
				int indexOfFirstAlphaNumeric = GetIndexOfFirstAlphaNumeric(text, num2);
				num2 = ((indexOfFirstAlphaNumeric < 0) ? num2 : indexOfFirstAlphaNumeric);
				int num3 = text.IndexOf("\r\n", num2);
				if (num3 < 0)
				{
					throw new NetworkException(-6413);
				}
				string text2 = text.Substring(num2, (num3 == 0) ? "\r\n".Length : (num3 - num2));
				list.Add(text2.Trim());
				num2 = num3 + "\r\n".Length;
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.GetHankshakeMessage);
			}
			return list;
		}

		private int GetIndexOfFirstAlphaNumeric(string message, int index)
		{
			for (int i = index; i < message.Length; i++)
			{
				if (char.IsLetterOrDigit(message, i))
				{
					return i;
				}
			}
			return -1;
		}

		private string GenerateResponseKey(string keyString)
		{
			string text = keyString + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
			byte[] bytes = Encoding.ASCII.GetBytes(text.Trim());
			return Convert.ToBase64String(new SHA1Managed().ComputeHash(bytes, 0, bytes.Length), 0, 20);
		}

		private void SendControlFrame(WebSocketDataFrame.WebSocketDataFrameOpcode opCode, byte[] controlData, int offset, int count)
		{
			if (opCode < WebSocketDataFrame.WebSocketDataFrameOpcode.CONNECTION_CLOSE || opCode > WebSocketDataFrame.WebSocketDataFrameOpcode.PONG)
			{
				throw new ArgumentException();
			}
			bool maskPayload = ((m_WebSocketRole == WebSocketRoles.WebSocketClient) ? true : false);
			m_snd_frame_buf.CreateWebSocketFrame(FinalSegment: true, opCode, maskPayload, 0u, count);
			Array.Copy(m_snd_frame_buf.FrameBuffer, m_snd_frame_buf.Length, controlData, offset, count);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.WebSocketStream, OracleTraceFuncName.Read, "WS out-going Control Frame :");
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.BulkCopy, m_snd_frame_buf.FrameBuffer, 0, m_snd_frame_buf.Length + count);
			}
			m_TcpStream.Write(m_snd_frame_buf.FrameBuffer, 0, m_snd_frame_buf.Length + count);
		}

		private static void _trace(string msg)
		{
			string text = new StackFrame(1).GetMethod()!.Name + "(): " + msg;
			OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Sqlnet, OracleTraceClassName.WebSocketStream, OracleTraceFuncName._trace, text);
		}
	}
}
